//go:build windows
// +build windows

// Package dll类 备注, 由go的syscall包复制过来修改的.
package 内部类

import (
	"fmt"
	"syscall"
	"unsafe"
)

var (
	kernel32                     = DLL载入("kernel32.dll")
	procCloseHandle              = kernel32.X命令("CloseHandle")
	procCreateToolhelp32Snapshot = kernel32.X命令("CreateToolhelp32Snapshot")
	procProcess32FirstW          = kernel32.X命令("Process32FirstW")
	procProcess32NextW           = kernel32.X命令("Process32NextW")
)

// X进程信息 是Windows进程的实现。
type X进程信息 struct {
	X进程ID  int
	X父进程ID int
	X进程名称  string
}

// ID取进程名 通过进程ID获取进程名称。
// 参数 进程ID: 要查询的进程ID。
// 返回值: 该进程ID对应的进程名称，如果找不到则返回空字符串。
func ID取进程名(进程ID int) string {
	// 获取系统中所有进程的信息。
	ps, _ := X枚举()
	// 遍历进程列表，寻找与给定PID匹配的进程。
	for _, p := range ps {
		// 当找到匹配的进程时，返回其名称。
		if p.X进程ID == 进程ID {
			return p.X进程名称
		}
	}
	// 如果没有找到匹配的进程，返回空字符串。
	return ""
}

// X枚举 使用Windows API枚举当前系统中的进程信息。
// 返回一个 进程信息 切片，以及在枚举过程中可能发生的错误。
// 来源 https://github.com/mitchellh/go-ps
func X枚举() ([]*X进程信息, error) {
	// 定义Windows路径最大长度常量
	const (
		MAX_PATH = 260
	)

	// PROCESSENTRY32 是Windows API结构体，包含进程的信息。
	type PROCESSENTRY32 struct {
		Size              uint32
		CntUsage          uint32
		ProcessID         uint32
		DefaultHeapID     uintptr
		ModuleID          uint32
		CntThreads        uint32
		ParentProcessID   uint32
		PriorityClassBase int32
		Flags             uint32
		ExeFile           [MAX_PATH]uint16
	}

	// 调用CreateToolhelp32Snapshot API获取进程快照。
	handle, _, _ := procCreateToolhelp32Snapshot.X调用(
		0x00000002, // 打开进程和线程快照的标志
		0)          // 无特定进程ID，表示所有进程
	if handle < 0 {
		return nil, syscall.GetLastError() // 如果句柄无效，返回最后的错误信息
	}
	defer procCloseHandle.X调用(handle) // 确保函数返回前关闭句柄

	// 初始化PROCESSENTRY32结构体变量
	var entry PROCESSENTRY32
	entry.Size = uint32(unsafe.Sizeof(entry))
	ret, _, _ := procProcess32FirstW.X调用(handle, uintptr(unsafe.Pointer(&entry)))
	if ret == 0 {
		return nil, fmt.Errorf("检索进程信息时出错。")
	}

	// 创建一个结果切片，用于存储进程信息
	results := make([]*X进程信息, 0, 50)
	for {
		// 处理当前进程信息
		e := &entry
		// 查找字符串结束位置
		end := 0
		for {
			if e.ExeFile[end] == 0 {
				break
			}
			end++
		}

		// 将进程信息添加到结果切片中
		results = append(results, &X进程信息{
			X进程ID:  int(e.ProcessID),
			X父进程ID: int(e.ParentProcessID),
			X进程名称:  syscall.UTF16ToString(e.ExeFile[:end]), // 将UTF16字符串转换为Go字符串
		})

		// 检索下一个进程信息
		ret, _, _ := procProcess32NextW.X调用(handle, uintptr(unsafe.Pointer(&entry)))
		if ret == 0 {
			break
		}
	}

	return results, nil // 返回枚举到的进程信息和nil错误
}
